home *** CD-ROM | disk | FTP | other *** search
- /* Driver for 3COM Ethernet card
- * PC specific code
- */
-
- #define TIMER 20000 /* Timeout on transmissions */
-
- #include <stdio.h>
- #include <dos.h>
- #include "global.h"
- #include "config.h"
- #ifdef PC_EC
- #include "mbuf.h"
- #include "enet.h"
- #include "iface.h"
- #include "pktdrvr.h"
- #include "netuser.h"
- #include "ec.h"
- #include "timer.h"
- #include "arp.h"
- #include "trace.h"
- #include "pc.h"
-
- #ifndef inportw /* previously in global.h */
- #define inportw inport
- #endif
-
- static int near ec_init __ARGS((struct iface *iface,unsigned bufsize));
- static int ec_raw __ARGS((struct iface *iface,struct mbuf *bp));
- static int ec_stop __ARGS((struct iface *iface,int tmp));
- static void near getecaddr __ARGS((unsigned base,char *cp));
- static void near rcv_fixup __ARGS((unsigned base));
- static void near setecaddr __ARGS((unsigned base,char *cp));
-
- static INTERRUPT (*Ecvecsave[EC_MAX])();
- static INTERRUPT (*Ecvec[])() = {ec0vec,ec1vec,ec2vec};
-
- static struct ec Ec[EC_MAX]; /* Per-controller info */
- static int Nec = 0;
-
- /* Initialize interface */
- static int near
- ec_init(iface,bufsize)
- struct iface *iface;
- unsigned bufsize; /* Maximum size of receive queue in PACKETS */
- {
- int dev = iface->dev;
- struct ec *ecp = &Ec[dev];
- unsigned base = ecp->base;
-
- ecp->iface = iface;
-
- /* Pulse IE_RESET */
- outportb(IE_CSR(base),IE_RESET);
-
- /* Save old int vector */
- Ecvecsave[dev] = getirq(ecp->vec);
-
- /* Set interrupt vector */
- if(setirq(ecp->vec,Ecvec[dev]) == -1){
- tprintf("IRQ %u out of range\n",ecp->vec);
- return -1;
- }
- maskon(ecp->vec); /* Enable interrupt */
- if(iface->hwaddr == NULLCHAR)
- iface->hwaddr = mxallocw(EADDR_LEN);
- getecaddr(base,iface->hwaddr);
- setecaddr(base,iface->hwaddr);
- if(memcmp(iface->hwaddr,Ether_bdcst,EADDR_LEN) == 0){
- tputs("EC address PROM contains broadcast address!!\n");
- return -1;
- }
- /* Enable DMA/interrupt request, gain control of buffer */
- outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
-
- /* Enable transmit interrupts */
- outportb(EDLC_XMT(base),EDLC_16 | EDLC_JAM);
-
- /* Set up the receiver interrupts and flush status */
- outportb(EDLC_RCV(base),
- EDLC_MULTI|EDLC_GOOD|EDLC_ANY|EDLC_SHORT|EDLC_DRIBBLE|EDLC_FCS|EDLC_OVER);
- inportb(EDLC_RCV(base));
-
- /* Start receiver */
- outport(IE_RP(base),0); /* Reset read pointer */
- outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
- return 0;
- }
-
- /* Send raw packet (caller provides header) */
- static int
- ec_raw(iface,bp)
- struct iface *iface; /* Pointer to interface control block */
- struct mbuf *bp; /* Data field */
- {
- int i;
- struct ec *ecp = &Ec[iface->dev];
- unsigned base = ecp->base;
- short size = len_p(bp);
-
- dump(iface,IF_TRACE_OUT,CL_ETHERNET,bp);
-
- ecp->estats.xmit++;
-
- /* Pad the size out to the minimum, if necessary,
- * with junk from the last packet (nice security hole here)
- */
- if(size < RUNT)
- size = RUNT;
-
- size = (size+1) & ~1; /* round size up to next even number */
-
- /* Wait for transmitter ready, if necessary. IE_XMTBSY is valid
- * only in the transmit mode, hence the initial check.
- */
- if((inportb(IE_CSR(base)) & IE_BUFCTL) == IE_XMTEDLC){
- for(i = TIMER; (inportb(IE_CSR(base)) & IE_XMTBSY) && i != 0; i--)
- ;
- if(i == 0) {
- ecp->estats.timeout++;
- free_p(bp);
- return -1;
- }
- }
- ecp->size = size;
- /* Get control of the board buffer and disable receiver */
- outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
- /* Point GP at beginning of packet */
- outport(IE_GP(base),BFRSIZ-size);
- /* Actually load each piece with a fast assembler routine */
- while(bp != NULLBUF){
- outbuf(IE_BFR(base),bp->data,bp->cnt);
- bp = free_mbuf(bp);
- }
- /* Start transmitter */
- outport(IE_GP(base),BFRSIZ-size);
- outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
- return 0;
- }
-
- /* Ethernet interrupt handler */
- void
- ecint(dev)
- int dev;
- {
- struct mbuf *bp;
- int16 size;
- char stat;
- struct phdr *phdr;
-
- struct ec *ecp = &Ec[dev];
- unsigned base = ecp->base;
-
- ecp->estats.intrpt++;
-
- /* Check for transmit jam */
- if(!(inportb(IE_CSR(base)) & IE_XMTBSY)){
- stat = inportb(EDLC_XMT(base));
- if(stat & EDLC_16){
- ecp->estats.jam16++;
- rcv_fixup(base);
- } else if(stat & EDLC_JAM){
- /* Crank counter back to beginning and restart transmit */
- ecp->estats.jam++;
- outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
- outport(IE_GP(base),BFRSIZ - ecp->size);
- outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
- }
- }
- for(;;){
- stat = inportb(EDLC_RCV(base));
- if(stat & EDLC_STALE)
- break;
-
- if(stat & EDLC_OVER){
- ecp->estats.over++;
- rcv_fixup(base);
- continue;
- }
- if(stat & (EDLC_SHORT | EDLC_FCS | EDLC_DRIBBLE)){
- ecp->estats.bad++;
- rcv_fixup(base);
- continue;
- }
- if(stat & EDLC_ANY){
- /* Get control of the buffer */
- outport(IE_GP(base),0);
- outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
-
- /* Allocate mbuf and copy the packet into it */
- size = inportw(IE_RP(base));
- if(size < RUNT || size > GIANT)
- ecp->estats.bad++;
- else if((bp = alloc_mbuf(size+sizeof(struct phdr))) == NULLBUF)
- ecp->estats.nomem++;
- else {
- ecp->estats.recv++;
- /* Generate descriptor header */
- phdr = (struct phdr *)bp->data;
- phdr->iface = ecp->iface;
- phdr->type = CL_ETHERNET;
-
- inbuf(IE_BFR(base),bp->data+sizeof(struct phdr),size);
- bp->cnt = size + sizeof(struct phdr);
- enqueue(&Hopper,bp);
- }
- outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
- outportb(IE_RP(base),0);
- }
- }
- /* Clear any spurious interrupts */
- (void)inportb(EDLC_RCV(base));
- (void)inportb(EDLC_XMT(base));
- }
-
- static void near
- rcv_fixup(base)
- unsigned base;
- {
- outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
- outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
- outportb(IE_RP(base),0);
- }
-
- /* Read Ethernet address from controller PROM */
- static void near
- getecaddr(base,cp)
- unsigned base;
- char *cp;
- {
- int i;
-
- for(i = 0; i < EADDR_LEN; i++) {
- outport(IE_GP(base),i);
- *cp++ = inportb(IE_SAPROM(base));
- }
- }
-
- /* Set Ethernet address on controller */
- static void near
- setecaddr(base,cp)
- unsigned base;
- char *cp;
- {
- int i;
-
- for(i = 0; i < EADDR_LEN; i++)
- outportb(EDLC_ADDR(base)+i,*cp++);
- }
-
- /* Shut down the Ethernet controller */
- static int
- ec_stop(iface,tmp)
- struct iface *iface;
- int tmp;
- {
- int dev = iface->dev;
- struct ec *ecp = &Ec[dev];
- unsigned base = ecp->base;
-
- /* Disable interrupt */
- maskoff(Ec[dev].vec);
-
- /* Restore original interrupt vector */
- setirq(ecp->vec,Ecvecsave[dev]);
-
- /* Pulse IE_RESET */
- outportb(IE_CSR(base),IE_RESET);
- outportb(IE_CSR(base),0);
- return 0;
- }
-
- /* Attach a 3-Com model 3C500 Ethernet controller to the system
- * argv[0]: hardware type, must be "3c500"
- * argv[1]: I/O address, e.g., "0x300"
- * argv[2]: vector, e.g., "3"
- * argv[3]: mode, must be "arpa"
- * argv[4]: interface label, e.g., "ec0"
- * argv[5]: maximum number of packets allowed on receive queue, e.g., "5"
- * argv[6]: maximum transmission unit, bytes, e.g., "1500"
- * notused:
- * argv[7]: IP address, optional (defaults to Ip_addr)
- */
- int
- ec_attach(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *if_ec;
- int dev;
-
- if(stricmp(argv[3],"arpa") != 0){
- tputs("Mode must be arpa\n");
- return -1;
- }
- if(if_lookup(argv[4]) != NULLIF) {
- tprintf(Ifexist,argv[4]);
- return -1;
- }
- if(Nec >= EC_MAX){
- tprintf("Max %d Ethernet controller/s\n",EC_MAX);
- return -1;
- }
- dev = Nec++;
- if_ec = mxallocw(sizeof(struct iface));
- if_ec->addr = Ip_addr;
- setencap(if_ec, "Ethernet");
- if_ec->name = strxdup(argv[4]);
- if_ec->mtu = atoi(argv[6]);
- if_ec->type = CL_ETHERNET;
- if_ec->send = enet_send;
- if_ec->output = enet_output;
- if_ec->raw = ec_raw;
- if_ec->stop = ec_stop;
- if_ec->dev = dev;
-
- Ec[dev].base = htoi(argv[1]);
- Ec[dev].vec = htoi(argv[2]);
-
- /* Initialize device */
- if(ec_init(if_ec,(unsigned)atoi(argv[5])) != 0){
- xfree(if_ec->name);
- xfree(if_ec);
- return -1;
- }
- if_ec->next = Ifaces;
- Ifaces = if_ec;
- if_ec->niface = Niface++;
- return 0;
- }
-
- int
- doetherstat(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct ec *ecp;
- char buf[20];
-
- for(ecp = Ec;ecp < &Ec[Nec]; ecp++){
- pether(buf,ecp->iface->hwaddr);
- tprintf("Controller %u, Ethernet address %s\n",
- (unsigned int)((ecp-Ec) / sizeof(struct ec)),buf);
-
- tprintf("recv bad overf drop nomem intrpt\n"
- "%-10lu%-10lu%-10lu%-10lu%-10lu%-10lu\n",
- ecp->estats.recv,ecp->estats.bad,ecp->estats.over,
- ecp->estats.drop,ecp->estats.nomem,ecp->estats.intrpt);
-
- tprintf("xmit timeout jam jam16\n"
- "%-10lu%-10lu%-10lu%-10lu\n",
- ecp->estats.xmit,ecp->estats.timeout,ecp->estats.jam,
- ecp->estats.jam16);
- }
- return 0;
- }
-
- #endif /* PC_EC */
-